package ch01.NodeGarden {

	/**
	 * 检测不只是为了碰撞，例子二(修复bug，源程序有bug)
	 * @author jianping.shenjp
	 */
	import ch01.GridCollision.CollisionGrid;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.utils.getTimer;
	import tools.Ball;

	[SWF(backgroundColor=0x000000)]
	public class NodeGardenLinesOpt extends Sprite {
		private var particles:Vector.<DisplayObject>;
		private var numParticles:uint = 500;
		private var minDist:Number = 50;
		private var springAmount:Number = .001;
		private var grid:CollisionGrid;
		private const RADIUS:Number = 3;
		private var _numChecks:int = 0;

		public function NodeGardenLinesOpt(){
			init();
		}

		private function init():void {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			/**
			 * 注意看网格大小和minDist（反应距离）一样是50，而不是粒子的半径。
			   记得为了获取最佳性能，要多做测试来得出合适的网格大小。
			   虽然一个更大的网格会带来更多的检测次数，但却会减少循环次数。
			   肯定存在一个最佳性能点，不过在这儿，最小值50 的性能也挺不错了。
			 */
			grid = new CollisionGrid(stage.stageWidth, stage.stageHeight, minDist);
			particles = new Vector.<DisplayObject>();
			for (var i:uint = 0; i < numParticles; i++){
				var particle:Ball = new Ball(RADIUS, 0xffffff);
				particle.x = Math.random() * stage.stageWidth;
				particle.y = Math.random() * stage.stageHeight;
				particle.vx = Math.random() * 6 - 3;
				particle.vy = Math.random() * 6 - 3;
				addChild(particle);
				particles.push(particle);
			}
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}

		private function onEnterFrame(event:Event):void {
			_numChecks = 0
			var startTime:int = getTimer();
			graphics.clear();
			for (var i:uint = 0; i < numParticles; i++){
				var particle:Ball = particles[i] as Ball;
				particle.x += particle.vx;
				particle.y += particle.vy;
                /**
                * 这里计算需要算上半径，否则会报错.
                */
				if (particle.x > stage.stageWidth - RADIUS){
					particle.x = RADIUS;
				} else if (particle.x < RADIUS){
					particle.x = stage.stageWidth - RADIUS;
				}
				if (particle.y > stage.stageHeight - RADIUS){
					particle.y = RADIUS;
				} else if (particle.y < RADIUS){
					//particle.y = stage.stageHeight-RADIUS;
					particle.y = stage.stageHeight - RADIUS;
				}
			}
			grid.check(particles);
			var checks:Vector.<DisplayObject> = grid.checks;
			var numChecks:int = checks.length;
			for (i = 0; i < numChecks; i += 2){
				var partA:Ball = checks[i] as Ball;
				var partB:Ball = checks[i + 1] as Ball;
				spring(partA, partB);
			}
			trace("3:Elapsed:", (getTimer() - startTime), "测试次数:", _numChecks, "checks.length", checks.length);
		}

		private function spring(partA:Ball, partB:Ball):void {
			_numChecks++;
			var dx:Number = partB.x - partA.x;
			var dy:Number = partB.y - partA.y;
			var dist:Number = Math.sqrt(dx * dx + dy * dy);
			if (dist < minDist){
				graphics.lineStyle(1, 0xffffff, 1 - dist / minDist);
				graphics.moveTo(partA.x, partA.y);
				graphics.lineTo(partB.x, partB.y);
				var ax:Number = dx * springAmount;
				var ay:Number = dy * springAmount;
				partA.vx += ax;
				partA.vy += ay;
				partB.vx -= ax;
				partB.vy -= ay;
			}
		}
	}
}